using Microsoft.Expression.Drawing.Core;
using System;
using System.Windows;
namespace Microsoft.Expression.Media
{
	internal class BlockArrowGeometrySource : GeometrySource<IBlockArrowGeometrySourceParameters>
	{
		private abstract class ArrowBuilder
		{
			public abstract double ArrowLength(Rect bounds);
			public abstract double ArrowWidth(Rect bounds);
			public abstract Point GetMirrorPoint(Point point, double width);
			public abstract Point ComputePointA(double length, double width);
			public abstract Point ComputePointB(double length, double offset);
			public abstract PointPair ComputePointCD(double length, double offset, double thickness);
		}
		private abstract class HorizontalArrowBuilder : BlockArrowGeometrySource.ArrowBuilder
		{
			public override double ArrowLength(Rect bounds)
			{
				return bounds.get_Width();
			}
			public override double ArrowWidth(Rect bounds)
			{
				return bounds.get_Height();
			}
			public override Point GetMirrorPoint(Point point, double width)
			{
				return new Point(point.get_X(), width - point.get_Y());
			}
		}
		private abstract class VerticalArrowBuilder : BlockArrowGeometrySource.ArrowBuilder
		{
			public override double ArrowLength(Rect bounds)
			{
				return bounds.get_Height();
			}
			public override double ArrowWidth(Rect bounds)
			{
				return bounds.get_Width();
			}
			public override Point GetMirrorPoint(Point point, double width)
			{
				return new Point(width - point.get_X(), point.get_Y());
			}
		}
		private class LeftArrowBuilder : BlockArrowGeometrySource.HorizontalArrowBuilder
		{
			public override Point ComputePointA(double length, double width)
			{
				return new Point(0.0, width / 2.0);
			}
			public override Point ComputePointB(double length, double offset)
			{
				return new Point(offset, 0.0);
			}
			public override PointPair ComputePointCD(double length, double offset, double thickness)
			{
				return new PointPair(new Point(offset, thickness), new Point(length, thickness));
			}
		}
		private class RightArrowBuilder : BlockArrowGeometrySource.HorizontalArrowBuilder
		{
			public override Point ComputePointA(double length, double width)
			{
				return new Point(length, width / 2.0);
			}
			public override Point ComputePointB(double length, double offset)
			{
				return new Point(length - offset, 0.0);
			}
			public override PointPair ComputePointCD(double length, double offset, double thickness)
			{
				return new PointPair(new Point(length - offset, thickness), new Point(0.0, thickness));
			}
		}
		private class UpArrowBuilder : BlockArrowGeometrySource.VerticalArrowBuilder
		{
			public override Point ComputePointA(double length, double width)
			{
				return new Point(width / 2.0, 0.0);
			}
			public override Point ComputePointB(double length, double offset)
			{
				return new Point(0.0, offset);
			}
			public override PointPair ComputePointCD(double length, double offset, double thickness)
			{
				return new PointPair(new Point(thickness, offset), new Point(thickness, length));
			}
		}
		private class DownArrowBuilder : BlockArrowGeometrySource.VerticalArrowBuilder
		{
			public override Point ComputePointA(double length, double width)
			{
				return new Point(width / 2.0, length);
			}
			public override Point ComputePointB(double length, double offset)
			{
				return new Point(0.0, length - offset);
			}
			public override PointPair ComputePointCD(double length, double offset, double thickness)
			{
				return new PointPair(new Point(thickness, length - offset), new Point(thickness, 0.0));
			}
		}
		private Point[] points;
		protected override bool UpdateCachedGeometry(IBlockArrowGeometrySourceParameters parameters)
		{
			bool flag = false;
			BlockArrowGeometrySource.ArrowBuilder builder = BlockArrowGeometrySource.GetBuilder(parameters.Orientation);
			double num = builder.ArrowLength(base.LogicalBounds);
			double num2 = builder.ArrowWidth(base.LogicalBounds);
			double num3 = num2 / 2.0 / num;
			double num4 = MathHelper.EnsureRange(parameters.ArrowheadAngle, new double?(0.0), new double?(180.0));
			double num5 = Math.Tan(num4 * 3.1415926535897931 / 180.0 / 2.0);
			if (num5 < num3)
			{
				this.EnsurePoints(3);
				this.points[0] = builder.ComputePointA(num, num2);
				this.points[1] = builder.ComputePointB(num, num);
				this.points[2] = builder.GetMirrorPoint(this.points[1], num2);
			}
			else
			{
				double offset = num2 / 2.0 / num5;
				double num6 = MathHelper.EnsureRange(parameters.ArrowBodySize, new double?(0.0), new double?(1.0));
				double thickness = num2 / 2.0 * (1.0 - num6);
				this.EnsurePoints(7);
				this.points[0] = builder.ComputePointA(num, num2);
				this.points[1] = builder.ComputePointB(num, offset);
				PointPair pointPair = builder.ComputePointCD(num, offset, thickness);
				this.points[2] = pointPair.Item1;
				this.points[3] = pointPair.Item2;
				this.points[4] = builder.GetMirrorPoint(this.points[3], num2);
				this.points[5] = builder.GetMirrorPoint(this.points[2], num2);
				this.points[6] = builder.GetMirrorPoint(this.points[1], num2);
			}
			for (int i = 0; i < this.points.Length; i++)
			{
				Point[] expr_24B_cp_0 = this.points;
				int expr_24B_cp_1 = i;
				expr_24B_cp_0[expr_24B_cp_1].set_X(expr_24B_cp_0[expr_24B_cp_1].get_X() + base.LogicalBounds.get_Left());
				Point[] expr_273_cp_0 = this.points;
				int expr_273_cp_1 = i;
				expr_273_cp_0[expr_273_cp_1].set_Y(expr_273_cp_0[expr_273_cp_1].get_Y() + base.LogicalBounds.get_Top());
			}
			return flag | PathGeometryHelper.SyncPolylineGeometry(ref this.cachedGeometry, this.points, true);
		}
		private static BlockArrowGeometrySource.ArrowBuilder GetBuilder(ArrowOrientation orientation)
		{
			switch (orientation)
			{
			case ArrowOrientation.Left:
				return new BlockArrowGeometrySource.LeftArrowBuilder();
			case ArrowOrientation.Up:
				return new BlockArrowGeometrySource.UpArrowBuilder();
			case ArrowOrientation.Down:
				return new BlockArrowGeometrySource.DownArrowBuilder();
			}
			return new BlockArrowGeometrySource.RightArrowBuilder();
		}
		private void EnsurePoints(int count)
		{
			if (this.points == null || this.points.Length != count)
			{
				this.points = new Point[count];
			}
		}
	}
}
